from typing import Optional, Dict, Any
from sqlalchemy.orm import Session
from fastapi import HTTPException, status

from app.services.user_service import user_service
from app.models.schemas import UserCreate, LoginRequest, UserResponse
from app.utils.auth import create_tokens, verify_token


class AuthService:
    """认证服务类"""

    def __init__(self):
        self.user_service = user_service

    def register(
        self, db: Session, *, user_data: UserCreate, mock_mode: bool = False
    ) -> Dict[str, Any]:
        """用户注册"""
        if mock_mode:
            # 模拟注册模式 - 不写入数据库，只做验证
            # 数据验证：检查用户名格式
            if len(user_data.username) < 3:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="用户名至少需要3个字符",
                )

            # 数据验证：检查邮箱格式
            if "@" not in user_data.email:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST, detail="邮箱格式不正确"
                )

            # 数据验证：检查密码强度
            if len(user_data.password) < 6:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail="密码至少需要6个字符",
                )

            # 返回模拟的成功注册响应
            mock_user = UserResponse(
                id=1001,  # 模拟用户ID
                username=user_data.username,
                email=user_data.email,
                full_name=user_data.full_name,
                phone=user_data.phone,
                description=user_data.description,
                is_active=True,
                is_superuser=False,
                avatar_url=None,
                created_at="2025-09-11T10:00:00",
                updated_at="2025-09-11T10:00:00",
            )

            return {"user": mock_user}

        # 正常注册模式 - 写入数据库
        # 验证用户名是否已存在
        if self.user_service.is_username_taken(db, user_data.username):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="用户名已存在"
            )

        # 验证邮箱是否已存在
        if self.user_service.is_email_taken(db, user_data.email):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="邮箱已存在"
            )

        # 创建用户
        user = self.user_service.create_user(db, user_in=user_data)

        # 生成令牌
        token_data = {"user_id": user.id, "username": user.username}
        tokens = create_tokens(token_data)

        return {"user": user, "tokens": tokens}

    def login(self, db: Session, *, login_data: LoginRequest) -> Dict[str, Any]:
        """用户登录"""
        user = self.user_service.authenticate(
            db, username=login_data.username, password=login_data.password
        )

        if not user:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="用户名或密码错误",
                headers={"WWW-Authenticate": "Bearer"},
            )

        if not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="用户账户已被禁用"
            )

        # 生成令牌
        token_data = {"user_id": user.id, "username": user.username}
        tokens = create_tokens(token_data)

        return {"user": user, "tokens": tokens}

    def refresh_token(self, db: Session, *, refresh_token: str) -> Dict[str, Any]:
        """刷新令牌"""
        payload = verify_token(refresh_token, token_type="refresh")
        if not payload:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的刷新令牌"
            )

        user_id = payload.get("user_id")
        username = payload.get("username")

        if not user_id or not username:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED, detail="无效的令牌载荷"
            )

        user = self.user_service.get(db, user_id)
        if not user or not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED, detail="用户不存在或已被禁用"
            )

        # 生成新令牌
        token_data = {"user_id": user.id, "username": user.username}
        tokens = create_tokens(token_data)

        return {"user": user, "tokens": tokens}

    def get_current_user(self, db: Session, *, token: str) -> Optional[Any]:
        """获取当前用户"""
        payload = verify_token(token)
        if not payload:
            return None

        user_id = payload.get("user_id")
        if not user_id:
            return None

        return self.user_service.get(db, user_id)

    def change_password(
        self, db: Session, *, user: Any, current_password: str, new_password: str
    ) -> Dict[str, str]:
        """修改密码"""
        # 验证当前密码
        from app.utils.auth import verify_password

        if not verify_password(current_password, user.hashed_password):
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, detail="当前密码错误"
            )

        # 更新密码
        self.user_service.update_password(db, user=user, new_password=new_password)

        return {"message": "密码修改成功"}

    def logout(
        self, db: Session, *, user_id: Optional[int] = None, token: str
    ) -> Dict[str, str]:
        """用户退出登录"""
        # 目前使用JWT无状态令牌，不需要在服务端做特殊处理
        # 如果需要实现token黑名单，可以在这里添加token到黑名单
        # 例如：将token添加到Redis黑名单中，在verify_token时检查

        # TODO: 可以在这里实现token黑名单逻辑
        # if user_id:
        #     redis_client.sadd(f"token_blacklist:{user_id}", token)
        # redis_client.sadd("token_blacklist", token)

        return {"message": "退出登录成功", "detail": "令牌已失效，请重新登录"}


# 创建全局实例
auth_service = AuthService()
